home *** CD-ROM | disk | FTP | other *** search
/ Almathera Ten Pack 3: CDPD 3 / Almathera Ten on Ten - Disc 3: CDPD3.iso / ab20 / ab20_archive / datacomm / xpr / xprkermit-1.111.lzh / kermitproto.w < prev    next >
Text File  |  1991-12-21  |  62KB  |  2,089 lines

  1. /*
  2.  * A completely new C Kermit module.
  3.  *
  4.  * Based on code from Frank Da Cruz's excellent book, _Kermit: A File
  5.  * Transfer Protocol_, Digital Press, 1986.
  6.  *
  7.  * As this code is almost entirely from said book, it is certainly covered
  8.  * by that book's copyright.  Basically, this means the code is freely
  9.  * distributable, and can be used in a commercial program provided such
  10.  * use does not increase the program's cost to the purchaser beyond a small
  11.  * handling fee.
  12.  *
  13.  * Stephen Walton, swalton@solar.stanford.edu
  14.  * Dept. of Physics and Astronomy
  15.  * California State University, Northridge
  16.  * Northridge, CA 91330
  17.  *
  18.  *            ORGANIZATION
  19.  *
  20.  *  This file is in three pieces, and could probably be broken into
  21.  * two files.  Leading off are #DEFINE's and declarations of
  22.  * global and external variables.  Following are the unmodified sources
  23.  * from The Book.   Then are the z* file-handling routines written using
  24.  * standard Unix-style (almost ANSI C) file routines.
  25.  *
  26.  * I make no apologies for the organization; my primary goals were (1) to
  27.  * use the unmodified book source except for errors found by Lint, and
  28.  * (2) to allow this file to be plugged into an otherwise unmodified
  29.  * terminal program for the Commodore Amiga computer called VT100.  The
  30.  * comments starting with the string "lint" are for the Lint program
  31.  * of Gimpel Software, available for the Commodore Amiga and MS-DOS
  32.  * machines.  I highly recommend it.
  33.  *
  34.  * A few words about style herein.  Both "book Kermit" and the official
  35.  * C Kermit release make extensive use of global variables to set various
  36.  * options and keep track of what is going on.  I don't like this, but
  37.  * since example source code must be part of the Kermit specification,
  38.  * I chose to keep that organization.  There are several places where I
  39.  * I have tried to modularize things better.  First of all, everything
  40.  * which is not needed outside of this file is declared "static".  Second,
  41.  * I have kept the book Kermit code pretty much intact, except for some lint
  42.  * related things and one extra convention:  tmsg() appends characters to
  43.  * an existing status line, but tmsgl() is required to force that output to
  44.  * be seen.  Hence, I've changed the last in each series of tmsg() calls to
  45.  * tmsgl().
  46.  */
  47.  
  48.  
  49. /*
  50.  * Revision History--Versions 0 through 1 never left me.
  51.  *
  52.  * Version 0.5--Created and linted.
  53.  * Version 0.6--Added RESUME to handling of "unknown packets".
  54.  *          --Added proto() function to wrap around wart() for handling
  55.  *        of startup and cleanup functions.
  56.  *          --Changed handling of timeouts in input():  instead of an
  57.  *        error("Timeout") call, it puts the "Timeout" message in
  58.  *        the data field and pretends it read an 'E' packet.
  59.  * Version 0.7--Fixed a problem with rpsiz and MAXRP.  I had set rpsiz
  60.  *        to MAXRP in rpar() and was calling ttinl() with a max
  61.  *        argument of MAXRP, which resulted in truncated packets;
  62.  *        to wit, MAXRP+1 characters could come into ttinl counting
  63.  *        the eol.  Created defines DRPSIZ/DSPSIZ for default values
  64.  *        for rpsiz and spsiz, and increased MAXRP.
  65.  *          --Changed rcvpkt, sndpkt, and data so that they are pointers
  66.  *        instead of static arrays, and allocate and de-allocate
  67.  *        them in proto().
  68.  * Version 0.8--Added client support.  To make a Get
  69.  *        command, point the char *cmarg at the remote file
  70.  *        specification and set the start state to 'r'
  71.  *        (extern char start in the calling file).
  72.  * Version 0.9--Added long packet support.  This required adding an extern
  73.  *        int urpsiz which is set to the desired receive packet size
  74.  *        by the user interface.
  75.  *          --Since the above required using the capas, I also added the
  76.  *        code from C Kermit 4E(070) for negotiating window size
  77.  *        in rpar() and spar(). Of course, we don't do windows yet.
  78.  *          --Fixed a bug which is also part of C Kermit 4E(070).
  79.  *        If we tell the sender that we can receive a packet
  80.  *        of size MAXRP, the packet can contain as many as
  81.  *        MAXRP+5 characters, counting the EOL and extended
  82.  *        headers.  So rpack() must be able to handle somewhat
  83.  *        more characters than the actual maximum packet length.
  84.  *        I defined MAXRP here to be 1024, but only allow
  85.  *        rpsiz in proto() to be MAXRP-20.
  86.  * Version 0.95--Added code to gracefully abort transfer.  This works
  87.  *        via the cx and cz external variables and the state 'a'.
  88.  * Version 1.0--Unleashed upon the world.
  89.  * Version 1.1--Marco Papa (papa on BIX, papa@pollux.usc.edu on Internet)
  90.  *        added the code between the #ifdef XPRKERMIT...#endif
  91.  *        pairs, which turns this code into a routine which can
  92.  *        be used as an Amiga external file transfer protocol.
  93.  *        Upon getting it back from him, I fixed two lingering
  94.  *        bugs:  there was an "if (ebqflg & b8)" in encode()
  95.  *        which should be &&, and the first argument of encode()
  96.  *        needed to be declared as an int, not a char.
  97.  *          --Allow user to set bctr (block check to request) himself.
  98.  *          --If urpsiz is illegal, we set rpsiz to a legal value;  I also
  99.  *        set urpsiz to this as well, so the user knows what's up.
  100.  * Version 1.2--Added a typedef of CHAR to unsigned char to allow this code
  101.  *        to work with the latest version of Wart (V 1A(006) dated
  102.  *        12 January 1989.
  103.  * Version 1.3--21 December 1989
  104.  *        (1)  Added a tflush() call to the end of decode().  This
  105.  *        gives the user an opportunity to flush out the messages
  106.  *        from X packets, if the I/O is buffered.
  107.  *
  108.  * Version 1.4-- 5 January 1989
  109.  *         (1) Added the counters for characters on a per-file and
  110.  *        per-transaction basis.  Later, we can use the per-file
  111.  *        ones and a timer to figure out how long we have to go
  112.  *        on the current file.
  113.  *        (2) Started replacing tchar() calls with calls to the
  114.  *        screen() function, again a la C Kermit.  #define's for
  115.  *        the manifest constants for screen() are in kermitproto.h,
  116.  *         copied from C Kermit.
  117.  *
  118.  * Version 1.6-- 18 August 1990 (Version 1.4 was released)
  119.  *        (1) Added ANSI-specific items, in particular the #include
  120.  *        of "kermitproto.h" and "xproto.h" which have all of the
  121.  *        prototypes.
  122.  *        (2) Fixed gnfile(), which was not being properly re-
  123.  *        initialized if a send was canceled.
  124.  *
  125.  * Version 1.63--2 December 1990
  126.  *        (1) Changed the behavior of the xpr chkint() function so
  127.  *        that the error exit is taken if (*xpr_chkabort)() returns
  128.  *        -1:  an error packet is made up and sent and the protocol
  129.  *        quits immediately.
  130.  *        (2) Discovered that the file character count in gnchar()
  131.  *        skipped nulls!  Fixed.
  132.  *
  133.  * Version 1.64--5 December 1990
  134.  *        Fixed zgetc(), which was hanging onto characters from the
  135.  *        previous file transfer if it was cancelled.
  136.  *
  137.  * Version 1.67--14 December 1990 (includes 1.65 through 1.67 changes)
  138.  *        Added buffered I/O from C Kermit 5A(163).
  139.  *        Replaced getpkt() with version from C Kermit 5A.  Got rid
  140.  *           of encode(), since it is built in.
  141.  *        Fixed a long standing block check 2 bug--a missing break
  142.  *           in the case statement in rpack()!
  143.  *
  144.  * Version  1.72--18 December 1990
  145.  *        Fixed *MAJOR* bugs in getpkt() from C Kermit:  maxsize()
  146.  *           is spurious, and should be bufmax;  and the leftover[]
  147.  *           array needs to be 7 characters long, not 6:  the worst
  148.  *           case is two successive eight-bit-quoted control chars.
  149.  */
  150.  
  151. /*
  152.  * Run this through the Wart preprocessor which comes with C Kermit.
  153.  */
  154.  
  155. #ifndef _lint
  156. static char rcsid[] = "$Header: Work:src/xprkermit/RCS/kermitproto.w,v 1.3 91/11/09 06:49:18 swalton Exp Locker: swalton $";
  157. #endif
  158.  
  159. #ifdef XPRKERMIT
  160. extern long (*xupdate)(), (*xswrite)(), (*xfopen)(), (*xfclose)(), (*xfread)(),
  161.      (*xfwrite)(), (*xsread)(),  (*xchkabort)(void), (*xffirst)(), (*xfnext)(),
  162.      (*xsflush)(void), (*xfinfo)(), (*xgets)(), (*xunlink)(), (*xsquery)(void),
  163.      (*xchkmisc)(void);
  164. extern long brkflag;
  165. #include "types.h"
  166. #include "xprkermit.h"
  167. #endif
  168.  
  169. #include "kermitproto.h"
  170. #include <stdlib.h>
  171. #include <string.h>
  172.  
  173.  
  174. /* kermitproto.c */
  175. static int input(void);
  176. static void errpkt(char *s);
  177. #pragma regcall(errpkt(a0))
  178. static int nxtpkt(void);
  179. static int tinit(void);
  180. static int error(char *s);
  181. #pragma regcall(error(a0))
  182. static int ack(void);
  183. static int ack1(char *s);
  184. #pragma regcall(ack1(a0))
  185. static int nak(void);
  186. static int sinit(int c);
  187. #pragma regcall(sinit(d0))
  188. static int scmd(int t, char *s);
  189. #pragma regcall(scmd(d0,a0))
  190. static int rinit(void);
  191. static void resetc(void);
  192. static int sfile(void);
  193. static int sdata(void);
  194. static int seof(char *s);
  195. #pragma regcall(seof(a0))
  196. static int seot(void);
  197. static int rcvfil(void);
  198. static int reof(char *);
  199. #pragma regcall(reof(a0))
  200. static void fstats(void);
  201. static int closof(int nokeep);
  202. #pragma regcall(closof(d0))
  203. static int spack(int type, int n, int len, CHAR *d);
  204. #pragma regcall(spack(d0,d1,d2,a0))
  205. static int resend(void);
  206. static int rpack(void);
  207. static unsigned chksum(CHAR *s);
  208. #pragma regcall(chksum(a0))
  209. static unsigned chk1(CHAR *s);
  210. #pragma regcall(chk1(a0))
  211. static unsigned chk3(CHAR *s);
  212. #pragma regcall(chk3(a0))
  213. static int getpkt(int maxlen);
  214. #pragma regcall(getpkt(d0))
  215. static int decode(void);
  216. static int encstr(char *s);
  217. #pragma regcall(encstr(a0))
  218. static int decstr(char *s);
  219. #pragma regcall(decstr(a0))
  220. static int spar(CHAR *s);
  221. #pragma regcall(spar(a0))
  222. static char *rpar(void);
  223. static int zclear(void);
  224. static int zopeni(char *name);
  225. #pragma regcall(zopeni(a0))
  226. static int zopeno(char *name);
  227. #pragma regcall(zopeno(a0))
  228. static int zclosi(void);
  229. static int zcloso(int discard);
  230. #pragma regcall(zcloso(d0))
  231. static int zrtol(char *s1, char *s2, int warn);
  232. #pragma regcall(zrtol(a0,a1,d0))
  233. static int zltor(char *s1, char *s2);
  234. #pragma regcall(zltor(a0,a1))
  235. static int zinfill(void);
  236. static int zoutdump(void);
  237. static int tflush(void);
  238.  
  239. /*
  240.  * Buffered I/O stuff stolen from real C Kermit
  241.  */
  242. #define INBUFSIZE 1024            /* Size of record buffer. */
  243. #define OBUFSIZE 1024            /* Size of output buffer. */
  244. #define MAXNAMELEN 256            /* Maximum file name length */
  245.  
  246. static CHAR *zinbuffer, *zoutbuffer;
  247. static CHAR *zinptr, *zoutptr;        /* Buffer pointers */
  248. static int zincnt, zoutcnt;            /* Buffer char counters */
  249.  
  250.  
  251. /* get the next char; sorta like a getc() macro */
  252. #define zminchar() (((--zincnt)>=0) ? ((int)(*zinptr++) & 0377) : zinfill())
  253.  
  254. /* stuff a character into the input buffer */
  255. #define zmstuff(c) zinptr--, *zinptr = c, zincnt++
  256.  
  257. /* put a character to a file, like putchar() macro */
  258. #define zmchout(c) \
  259. ((*zoutptr++=(CHAR)(c)),(((++zoutcnt)>=OBUFSIZE)?zoutdump():0))
  260.  
  261. /*
  262.  * Here are the variables which need to be set to startup values, and which
  263.  * also can be freely changed between protocol transfers.  At first I thought
  264.  * to declare them all "extern" in order to force definition elsewhere.
  265.  * On reflection, it makes sense to both declare them here and set them to
  266.  * their default startup values.  Thus they can be ignored outside of this
  267.  * module if you so desire.
  268.  *
  269.  * Note that the names are very systematic:  Names beginning with "r" have
  270.  * to do with values I use for received packets;  those beginning with "s"
  271.  * are values I use for sending packets.  Also note we set some, others are
  272.  * set for us.  I have made the ones we get in spar() static (local),
  273.  * and the ones we send in rpar() global.
  274.  *
  275.  * First the ints.
  276.  */
  277.  
  278. int    cx = 0,
  279.     cz = 0,        /* Flags for aborting transfers.  cx (control-X)*
  280.              * is set to 1 if an abort of the current file    *
  281.              * is desired, cz (control-Z) if an abort of    *
  282.              * an entire batch transfer is desired.        */
  283.     rpsiz = MAXRP,    /* Maximum packet size                */
  284.             /* Like most of the receive packet parameters,    *
  285.              * this one is actually set by the sender.  But    *
  286.              * since the sender has the option to not send    *
  287.              * these, we must initialize to "reasonable"    *
  288.              * defaults.                    */
  289.     bctr = 1,    /* Block check type to request.            */
  290.     limit = 5,    /* Retry limit on receive            */
  291.     warn = 0,    /* 1 for warn before overwriting files        */
  292.     keep = 0,    /* 1 to keep incomplete files            */
  293.     rpadn = 0,    /* Number of pad characters I require.        */
  294.     rtimo = 10;    /* How long I want you to wait before you    *
  295.              * you time me out.                */
  296.  
  297. CHAR    rmark = '\1',    /* Start of packet marker for receive        */
  298.     reol = '\r',    /* End of packet marker for receive        */
  299.     start = 0,    /* Start state                    */
  300.     sctlq = '#',    /* Control character quote character for send    */
  301.     rpadc = '\0';    /* Pad character I want you to use        */
  302.  
  303. /*
  304.  * Variables which MUST be set by the external interface.
  305.  */
  306. extern int
  307.     parity,        /* 0 for no parity--need for proper 8th-bit quote */
  308.     text,        /* Flag 1 for text file, 0 for binary file    */
  309.     urpsiz;        /* Maximum receive packet size user wants.    */
  310.  
  311. extern char
  312.     *cmarg;        /* Character string containing Kermit server cmd */
  313.  
  314. /*
  315.  * Variables having to do with the status of the file transfer.
  316.  */
  317. static long tfc,    /* File chararacters sent/received, total. */
  318.         ffc,    /*   "       "           "        , current file. */
  319.         timeouts,    /* Number of timeouts */
  320.         tlci,    /* Comm line characters in, total. */
  321.         flci,    /*   "    "      "       ", current file. */
  322.         tlco,    /*   "    "      "       ", total. */
  323.         flco;    /*   "    "      "       ", current file. */
  324. /*
  325.  * In a fit of cleverness, here are some macro defines for variables we *
  326.  * aren't currently using. Only now we tell Lint to ignore constant    *
  327.  * Booleans!
  328.  */
  329.  
  330. /*lint -e506 */
  331.  
  332. #define local 1        /* Local mode flag--that is, I'm on your end    */
  333. #define server 0    /* We are never server                */
  334. #define delay 0        /* Time to delay before sending first packet    */
  335. #define xpkt 0        /* Send X packet instead of F?            */
  336.  
  337. /*
  338.  * This block of defines is strictly internal flags of various kinds.    *
  339.  * I hope to Grid that I've got them all.  Someday this will be cleaner *
  340.  */
  341. static int
  342.     spsiz = DSPSIZ,    /* Maximum send packet size            */
  343.     wsize = MAXWS,    /* Maximum window size                */
  344.     sndpkl,        /* Size of packet currently being attempted    */
  345.     filcnt,        /* Number of files transferred so far        */
  346.     bctu = 1,    /* Block check type to use            */
  347.     rqf,        /* Flag for 8th bit quote negotiations        */
  348.     ebqflg = 0,    /* 8th-bit quoting flag                */
  349.     xflag,        /* Output to screen for generic server commands    */
  350.     rq = 0,        /* Received 8bq bid                */
  351.     rpt = 0,    /* Repeat count                    */
  352.     rptflg = 0,    /* Repeat processing flag            */
  353.     capas = 10,    /* Final position of inbound capas mask        */
  354.     atcapr = 0,    /* Attribute capability requested        */
  355.     atcapu = 0,    /* Attribute capability used            */
  356.     swcapr = 0,    /* Sliding windows capability requested        */
  357.     swcapu = 0,    /* Sliding windows capability used        */
  358.     lpcapr = 0,    /* Long packets capability requested        */
  359.     lpcapu = 0,    /* Long packets capability used            */
  360.     rsn,        /* Received sequence number            */
  361.     seq = 0,    /* Current sequence number            */
  362.     rln,        /* Length of received data field        */
  363.     size,        /* Current size of output packet data        */
  364.     first = 0,    /* Some kind of lookahead flag            */
  365.     stimo = 5,    /* Timeout interval for me to use        */
  366.     spadn = 0;    /* Number of pad characters for me to use    */
  367.  
  368. #define atcapb 8    /* Attribute capability bit            */
  369. #define swcapb 4    /* Sliding windows capability bit        */
  370. #define lpcapb 2    /* Long packets capability bit            */
  371. #define closif zclosi    /* I use closif() to close the input file in    *
  372.              * case it needs to be more complex later, but    *
  373.              * for now it just calls the z routine.        */
  374.  
  375. static char
  376.     filnam[MAXNAMELEN], /* Current file name            */
  377.         myname[MAXNAMELEN], /* Current local file name            */
  378.     ssc,        /* Start server command                */
  379.     memstr,        /* Use in-memory string?            */
  380.     *osp = NULL;    /* Output string pointer            */
  381.  
  382. static CHAR
  383.     smark = '\1',    /* Start of packet marker for send        */
  384.     spadc = '\0',    /* Pad character to use on sending        */
  385.     seol = '\r',    /* End of packet marker for sending        */
  386.     rctlq = '#',    /* Control character quote char for receiving    */
  387.     ebq = '&',    /* 8th-bit prefix                */
  388.     sq = 'Y',    /* Sent 8bq bid                    */
  389.     rptq = '~',    /* Repeat prefix                */
  390.     *memptr = NULL,    /* Pointer to characters in memory        */
  391.     *sndpkt,    /* Send packet.                    */
  392.     *rcvpkt,    /* Receieve packet.                */
  393.     *data,        /* Data to send/receive before encode/decode    */
  394.     *rdatap;    /* Pointer to null-terminated data field    */
  395.  
  396. #define ERR(s) error(s); RESUME
  397. #define RESUME return
  398.  
  399. /*lint -save -e525 -e527    We don't care how Wart formats!        */
  400. /*lint -e716 -e744 -e570 -esym(745,wart)    Other Wart peculiarities */
  401.  
  402. %states ssfil ssdat sseot
  403. %states srini srfil srdat
  404. %states sipkt srgen
  405. %%
  406.  
  407.  /* Start states */
  408.  
  409. s {                    /* - Start State - */
  410.     tinit();                /* Initialize transaction */
  411.     if (sinit('S') < 0) { ERR("sinit"); }    /* Build, send Send-Init. */
  412.     else {                /* If successful, */
  413.     filcnt = 0;            /* initialize file counter */
  414.     BEGIN ssfil;            /* and switch to ssfil state. */
  415.     }
  416. }
  417. v { tinit(); rinit(); BEGIN srini; }    /* - Receive - */
  418.  
  419. r {                    /* Get */
  420.     tinit(); ssc = 0;
  421.     if (sinit('I') < 0) { ERR("sinit"); }
  422.     else BEGIN sipkt;
  423. }
  424.  
  425. c {                    /* Host */
  426.     tinit(); ssc = 'C';
  427.     if (sinit('I') < 0) { ERR("sinit"); }
  428.     else BEGIN sipkt;
  429. }
  430.  
  431. g {                    /* Generic */
  432.     tinit(); ssc = 'G';
  433.     if (sinit('I') < 0) { ERR("sinit"); }
  434.     else BEGIN sipkt;
  435. }
  436.  
  437. a {                    /* Immediate protocol abort */
  438.     spack('E', seq, 21, (CHAR *) "User aborted protocol");
  439.     closif();  closof(1);        /* Close files, deleting output */
  440.     RESUME;
  441. }
  442.  
  443. /* Dynamic states, sending file(s) */
  444.  
  445. <ssfil>Y {                /* - Send File State - */
  446.     if (filcnt++ == 0) spar(rdatap);    /* Set parameters if 1st time */
  447.     cx = 0;                /* Reset file interruption flag */
  448.     bctu = bctr;            /* Switch to negotiated block check */
  449.     resetc();                /* Reset global counters. */
  450. #ifdef XPRKERMIT
  451.     ST_Display_CRC(bctu);
  452. #endif
  453.     /* Is there a file to send in an uncancelled batch? */
  454.     if (!cz && gnfile(filnam, sizeof(filnam)) > 0) {
  455.     if (sfile() < 0) { ERR("sfile"); }    /* Yes, open it, send F packet */
  456.     else BEGIN ssdat;        /* and if no error, switch state. */
  457.     } else {                /* No (more) files to send */
  458.     if (seot() < 0) { ERR("seot"); }    /* so send B packet */
  459.     else BEGIN sseot;        /* and switch to sseot state. */
  460.     }
  461. }
  462. <ssdat>Y {                /* - Send Data State - */
  463.     int x;
  464.     if (rln == 1 && *rdatap == 'X')    /* Did ACK contain X as data? */
  465.     cx = 1;                /* Yes, set control-x flag. */
  466.     else if (rln == 1 && *rdatap == 'Z') /* Did ACK contain Z as data? */
  467.     cz = 1;                /* Yes set control-z flag. */
  468.     /* Check here for cancellation of transfer and data left to send. */
  469.     if (cx || cz || (x = sdata()) == 0) {
  470.     if (seof((cx || cz) ? "D" : "") < 0) {    /* If not, send Z packet. */
  471.         ERR("seof");
  472.     }
  473.     else BEGIN ssfil;        /* and go back to ssfil state. */
  474.     } else if (x < 0) { ERR("sdata"); }    /* Handle file i/o errors. */
  475. }
  476. <sseot>Y { RESUME; }            /* - Send B, done. */
  477.  
  478. /* Dynamic states, receiving file(s) */
  479.  
  480. <srini,srgen>S {
  481.     resetc();
  482.     spar(rdatap);
  483.     (void) ack1(rpar());
  484.     bctu = bctr;
  485.     BEGIN srfil;
  486. }
  487.  
  488. <srfil>B { (void) ack(); RESUME; }
  489.  
  490. <srfil>F { if (rcvfil() < 0) { ERR("rcvfil"); } else { (void) ack(); BEGIN srdat; } }
  491.  
  492. <srdat>D {
  493.    if (cx)
  494.     ack1("X");
  495.    else if (cz)
  496.     ack1("Z");
  497.    else    if (decode() < 0) {
  498.     ERR("Error writing data");
  499.    } else
  500.     (void) ack();
  501. }
  502.  
  503. <srdat>Z {
  504.     if (reof(filnam) < 0) {        /* Close & dispose of the file */
  505.     errpkt("Can't close file");    /* If problem, send error message */
  506.     RESUME;                /* and quit */
  507.     } else {                /* otherwise */
  508.     ack();                /* acknowledge the EOF packet */
  509.     BEGIN srfil;            /* and await another file */
  510.     }
  511. }
  512.  
  513. /* Dynamic states, server mode */
  514.  
  515. <sipkt>Y {            /* Got ACK for I packet */
  516.     spar(rdatap);        /* Set parameters from it */
  517.     start = 'E';        /* Force entry into next state */
  518. }
  519.  
  520. <sipkt>E {            /* Got E for I packet */
  521.     if (ssc) {
  522.     if (scmd(ssc,cmarg) < 0) { ERR("scmd"); }
  523.     else BEGIN srgen;
  524.     } else {
  525.     if (scmd('R',cmarg) < 0) { ERR("scmd"); }
  526.     else BEGIN srini;
  527.     }
  528. }
  529.  
  530. <srgen>Y { xflag = 1; decode(); RESUME; }
  531.  
  532. <srgen,srfil>X { xflag = 1; decode(); ack(); BEGIN srdat; }
  533.  
  534. /* Error state */
  535.  
  536. E { error((char *) rdatap);
  537.     (void) closif();
  538.     (void) closof(1);        /* close files, discarding output */
  539.     RESUME; }
  540.  
  541. . { error("Unexpected packet type"); RESUME; }
  542.                 /* Handle unwanted packet types. */
  543. %%
  544.  
  545. /*lint -restore -esym(551,tlci,tlco,flci,flco,rptn,atcapu,tfc) */
  546.  
  547. static void
  548. errpkt(char *msg) {
  549.     spack('E', seq, (int) strlen(msg), (CHAR *) msg);
  550. }
  551.  
  552. static
  553. int
  554. input() {                /* Return packets    */
  555.     int type, try;
  556.  
  557.     if (start != 0) {            /* Start state in effect? */
  558.     type = start;            /* Yes, call it a packet type, */
  559.     start = 0;            /* nullify the start state, */
  560.     return(type);            /* and return the type. */
  561.     }
  562.     for (try = 0; ; try++) {
  563.     type = rpack();            /* No start state, read a packet. */
  564.     /*
  565.      * Some checks we do every packet.
  566.      */
  567.     if (try > limit) {        /* If too mahy tries, */
  568.         strcpy((char *) data, "Too many retries");    /* give up */
  569.         rdatap = data;        /* Make up pretend 'E' packet */
  570.         type = 'E';            /* and return it */
  571.         break;
  572.     }
  573. #ifdef XPRKERMIT
  574.     if (xchkmisc)
  575.             (void) (*xchkmisc)();
  576. #endif
  577.     if (chkint() < 0) {        /* Check for console interrupt. */
  578.         errpkt("User cancelled.");
  579.         strcpy((char *) data, "User cancelled.");
  580.         rdatap = data;
  581.         type = 'E';
  582.         break;
  583.     }
  584.     /*
  585.      * Now see if we got the packet we want.
  586.      */
  587.     if (rsn == seq && strchr("TQN",type) == 0)    /* packet we want */
  588.         break;
  589.     else if (type == 'N' && rsn == ((seq + 1) & 63)) {
  590.                     /* NAK for next packet */
  591.         type = 'Y';            /* is ACK for current. */
  592.         break;
  593.     } else {            /* Otherwise, */
  594.         (void) resend();        /* resend previous packet. */
  595.     }
  596.     }
  597.     ttflui();                /* Got a good one, clear buffer. */
  598.     return(type);            /* Return its type. */
  599. }
  600.  
  601. static
  602. nxtpkt() {
  603.     seq = (seq + 1) & 63;        /* Next packet number, mod 64 */
  604. }
  605.  
  606. /*  R E S E T C  --  Reset per-transaction character counters */
  607. static void resetc(void) {
  608.     tfc = tlci = tlco = 0;    /* Total file chars, line chars in & out */
  609.     timeouts = 0;        /* Timeouts */
  610. }
  611.  
  612. static
  613. tinit() {                /* Transaction initialization */
  614.     seq = 0;                /* Start off with packet 0 */
  615.     ebqflg = 0;                /* 8-bit quoting off */
  616.     sq = 'Y';                /* Normal 8-bit quote bid */
  617.     rqf = -1;                /* Flag other's bid not yet seen */
  618.     rptflg = 0;                /* No repeat counts by default */
  619.     bctu = 1;                /* Block check to use back to 1 */
  620.     xflag = 0;                /* Output normally to file */
  621.     memstr = 0;                /* Reset memory-string flag */
  622.     memptr = NULL;            /*  and poiinter */
  623.     osp = NULL;                /* ... */
  624.     cx = cz = 0;            /* Reset interrupt flags */
  625.     *filnam = *sndpkt = *rcvpkt = '\0';  /* Clear string buffers */
  626.     spsiz = rpsiz;            /* Initial send-packet size */
  627. }
  628.  
  629. static
  630. error(s) char *s; {            /* Fatal error */
  631.     if (local) {            /* If in local mode */
  632.     screen(SCR_EM,0,0L,s);        /* Type message on console */
  633.     } else {                /* Otherwise, */
  634.     (void) spack('E',seq,(int) strlen(s), (CHAR *) s); /* Send in error packet. */
  635.     }
  636.     return;
  637. }
  638.  
  639. static
  640. ack() {
  641.     int x;                /* Empty acknowledgement */
  642.     x = spack('Y',seq,0,(CHAR *) "");    /* Send the packet */
  643.     nxtpkt();                /* Increment the packet number */
  644.     return(x);
  645. }
  646.  
  647. static
  648. ack1(s) char *s; {
  649.     int x;                /* Acknowledgement with data */
  650.     x = spack('Y',seq,(int)strlen(s),(CHAR *)s);
  651.     nxtpkt();                /* Increment packet number */
  652.     return(x);
  653. }
  654.  
  655. static
  656. nak() {                    /* Negative acknowledgement */
  657.     return(spack('N',seq,0,(CHAR *)""));    /* Never has data! */
  658. }
  659.  
  660. /* Functions used by file sender. */
  661.  
  662. /* sinit()--start the transaction by filling in the initialization string
  663.  * and sending it in an S packet.
  664.  */
  665.  
  666. static
  667. sinit(c) char c; {
  668.     char *s;
  669.  
  670.     gninit();                /* Initialize gnfile() function. */
  671.     s = rpar();
  672.     if (local == 0 && c == 'S' && server == 0) {
  673. #ifdef XPRKERMIT
  674.     ST_Display_String(STMsg,"Escape back to local system, RECEIVE command");
  675. #else
  676.     tmsgl("Escape back to local system, give RECEIVE command...");
  677. #endif
  678.     sleep(delay);
  679.     }
  680.     return(spack(c,seq,(int)strlen(s),(CHAR *)s));
  681. }
  682.  
  683. /*
  684.  * scmd() -- send a preformatted Kermit server command string.
  685.  */
  686. static
  687. scmd(t, s) char t, *s; {    /* Send a packet of the given type */
  688.     encstr(s);            /* Encode the command string */
  689.     spack(t,seq,size,data);
  690. }
  691.  
  692. /* rinit() -- do whatever is needed to initialize receive.  Now a no-op.
  693.  */
  694. static
  695. rinit()
  696. {
  697. }
  698.  
  699. /* sfile() -- open the file and send the File-Header packet.  Assumes that
  700.  * the global string pointer filnam references the file name.
  701.  */
  702.  
  703. static
  704. sfile() {
  705.     int x;
  706.     char pktnam[MAXNAMELEN];
  707.     if (zopeni(filnam) < 0)        /* Try to open file. */
  708.     return -1;
  709.     zltor(filnam,pktnam);        /* OK, convert name. */
  710.     x = encstr(pktnam);            /* Encode the result */
  711.     if (local) {            /* If in local mode, */
  712. #ifdef XPRKERMIT
  713.     ST_Display_String(STFile, pktnam);
  714.     ST_Display_String(STUplSize, filnam);
  715. #else
  716.     tmsg("Sending ");        /* let user know we're */
  717.     tmsg(filnam);            /* sending this file */
  718.     tmsg(" as ");            /* under */
  719.     tmsgl(pktnam);            /* this name */
  720. #endif
  721.     }
  722.     first = 1;                /* Flag beginning of file */
  723.     ffc = flci = flco = 0;        /* Zero per-file char count */
  724.     nxtpkt();                /* Increment packet number */
  725.     return(spack((xpkt ? 'X' : 'F'),seq,x,data)); /* Send packet */
  726. }
  727.  
  728. /* sdata() -- get next packet's worth of data */
  729.  
  730. static
  731. sdata() {
  732.     int x;
  733.  
  734.     if (spsiz > 94)            /* Long packets */
  735.         x = getpkt(spsiz - bctu - 6);
  736.     else                /* Short packets. */
  737.         x = getpkt(spsiz - bctu - 3);
  738.     if (x == 0)                /* If no data left to send, */
  739.     return(0);            /* return EOF indication. */
  740.     nxtpkt();
  741.     return(spack('D',seq,x,data));    /* Send the data packet */
  742. }
  743.  
  744. /* seof -- close the input file and send a Z packet. */
  745.  
  746. static
  747. seof(s) char *s; {
  748.     if (closif() < 0)            /* Try to close the file. */
  749.     return -1;            /* On error, return failure. */
  750.     else {                /* Otherwise, */
  751. #ifdef XPRKERMIT
  752.     if (local) ST_Display_String(STMsg,"OK");
  753. #else
  754.     if (local) tmsgl("OK");        /* if local, reassure user. */
  755. #endif
  756.     nxtpkt();
  757.     return(spack('Z',seq,(int)strlen(s),(CHAR *) s)); /* Send Z packet */
  758.     }
  759. }
  760.  
  761. /* seot -- send B packet. */
  762.  
  763. static
  764. seot() {
  765.     nxtpkt();
  766. #ifdef XPRKERMIT
  767.     if (local) ST_Display_String(STMsg,"Done");
  768. #else
  769.     if (local) tmsgl("Done");
  770. #endif
  771.     return(spack('B',seq,0,(CHAR *) ""));
  772. }
  773.  
  774. static
  775. rcvfil() {                /* Receive a file */
  776.  
  777.     ffc = flci = flco = 0;        /* Initialize per-file char count */
  778.     decstr(filnam);            /* Decode name */
  779.     zrtol(filnam,myname,warn);        /* Convert to local form. */
  780.     if (zopeno(myname) < 0)
  781.     return -1;
  782.     else {                /* File open OK, give message. */
  783.     if (local && !xflag) {
  784. #ifdef XPRKERMIT
  785.         ST_Display_String(STFile,myname);
  786.         ST_Display_CRC(bctu);
  787. #else
  788.         tmsg("Receiving "); tmsg(filnam); tmsg(" as "); tmsgl(myname);
  789. #endif
  790.     }
  791.     return 0;
  792.     }
  793. }
  794.  
  795. /*  R E O F  --  Receive End Of File  */
  796.  
  797. static
  798. reof(f) char *f; {
  799.     int x;
  800.     char *p;
  801.  
  802.     if (cx == 0) cx = (*rdatap == 'D');        /* Got discard directive? */
  803.     x = closof((cx || cz) && (keep == 0));
  804.     if (cx || cz) {
  805.     cx = 0;
  806.     if (keep)
  807.       p = "*** Incomplete file";
  808.     else
  809.       p = "*** Discarding file";;
  810.     screen(SCR_EM, 0, 0L, p);
  811.     } else {
  812.     fstats();
  813.     }
  814.     *filnam = '\0';
  815.     return(x);
  816. }
  817.  
  818. static void                /* Update statistics */
  819. fstats() {
  820.     tfc += ffc;
  821. }
  822.  
  823. static
  824. closof(nokeep) int nokeep; {        /* Close output file, but */
  825.     if (xflag) return 0;        /* not if it's the screen. */
  826.     if (zcloso(nokeep) < 0)
  827.     return -1;
  828.     return 0;
  829. }
  830.  
  831. static
  832. spack(type,n,len,d) char type; int n, len; CHAR *d; {
  833.     int i = 0, j, k;
  834.     unsigned int x;
  835.     CHAR *sohp;                /* Mark start of packet data. */
  836.  
  837.     for (i = 0; i < spadn; i++)
  838.     sndpkt[i] = spadc;        /* Do requested padding */
  839.     sohp = sndpkt + i;
  840.     sndpkt[i++] = smark;        /* Packet mark */
  841.     k = i++;                /* Remember this place */
  842.     sndpkt[i++] = tochar(n);        /* Sequence number */
  843.     sndpkt[i++] = (CHAR) type;        /* Packet type */
  844.     j = len + bctu;            /* True length */
  845.     if (j > 92) {            /* Long packet? */
  846.     sndpkt[k] = tochar(0);        /* Set LEN to 0 */
  847.     sndpkt[i++] = tochar(j / 95);    /* High part of length */
  848.     sndpkt[i++] = tochar(j % 95);    /* Low part of length */
  849.     sndpkt[i] = '\0';        /* Header checksum */
  850.     sndpkt[i++] = tochar(chk1(sndpkt+k));
  851.     } else
  852.     sndpkt[k] = tochar(j+2);    /* True length. */
  853.  
  854.     for (j = len; j > 0; j--) {        /* Data */
  855.     sndpkt[i++] = *d++;
  856.     }
  857.     sndpkt[i] = '\0';            /* Null terminate. */
  858.     switch (bctu) {
  859.     case 1:                /* Type 1 - 6 bit checksum */
  860.         sndpkt[i++] = tochar(chk1(sndpkt+k));
  861.         break;
  862.     case 2:                /* Type 2 - 12 bit checksum */
  863.         x = chksum(sndpkt+k);
  864.         sndpkt[i++] = tochar((x >> 6) & 077);
  865.         sndpkt[i++] = tochar(x & 077);
  866.         break;
  867.     case 3:                /* Type 3 - 16 bit CRC-CCITT */
  868.         x = chk3(sndpkt + k);
  869.         sndpkt[i++] = tochar((x >> 12) & 017);
  870.         sndpkt[i++] = tochar((x >> 6) & 077);
  871.         sndpkt[i++] = tochar(x & 077);
  872.         break;
  873.     default:
  874.         return -1;            /* Error message here? */
  875.     }
  876.     sndpkt[i++] = seol;            /* End of line */
  877.     sndpkt[i] = '\0';            /* Null string-terminat    or. */
  878.     sndpkl = i;                /* Remember length. */
  879.     i = ttol((char *) sndpkt,sndpkl);    /* Send the packet. */
  880.     tlco += sndpkl;            /* Count characters output. */
  881.     flco += sndpkl;
  882.     screen(SCR_PT, type, (long) n, (char *) sohp);
  883.     return(i);
  884. }
  885.  
  886. static
  887. resend() {
  888.     int x;
  889.     if (*sndpkt)
  890.     x = ttol((char *) sndpkt,sndpkl); /* Send previous packet */
  891.     else
  892.     x = nak();            /* or NAK if none */
  893.     if (local && !xflag) tchar('%');    /* Let the user know. */
  894.     return(x);
  895. }
  896.  
  897. static unsigned
  898. chk1(packet) CHAR *packet; {        /* Compute Kermit's */
  899.     unsigned s, t;            /* 1-character block check. */
  900.     s = chksum(packet);            /* Get the arithmetic sum. */
  901.     t = (((s & 192) >> 6) + s) & 63;    /* Fold it into 6 bits. */
  902.     return(t);
  903. }
  904.  
  905. static unsigned
  906. chksum(p) CHAR *p; {            /* Compute the checksum. */
  907.     unsigned m;
  908.     long s;
  909.  
  910.     m = (parity) ? 0177 : 0377;        /* Mask for parity bit.    */
  911.     s = 0;
  912.     for (; *p != '\0'; p++)        /* For each character, */
  913.     s += *p & m;            /* accumulate the sum, */
  914.     return(s & 07777);            /* and then return it. */
  915. }
  916.  
  917. /*
  918.  * rpack reads a packet and returns the packet type, or else Q if the
  919.  * packet was invalid, or T if a timeout occured.   Upon successful return,
  920.  * sets the global variables:
  921.  *    rsn    - the received sequence number
  922.  *    rln    - length of the received data field
  923.  *    rdatap    - a pointer to the null-terminated contents of the data field
  924.  */
  925. static
  926. rpack() {
  927.     int i, j, type, rlnpos;
  928.     unsigned x;
  929.     CHAR pbc[4];            /* Packet block check. */
  930.     CHAR *sohp;                /* Start of packet data. */
  931.  
  932.     rsn = rln = -1;            /* In case of failure. */
  933.  
  934.     *rcvpkt = '\0';            /* Initialize receive buffer. */
  935.     j = ttinl((char *) rcvpkt,MAXRP,reol,stimo);
  936.     if (j < 0) {
  937.         if (j == -1) {
  938.             screen(SCR_PT, 'T', (long) rsn, "");
  939.         return('T');        /* Timed out. */
  940.     } else
  941.         return(j);
  942.     }
  943.  
  944.     tlci += j;                /* Count received characters. */
  945.     flci += j;                /* On per-file basis. */
  946.     for (i = 0; rcvpkt[i] != rmark && (i < j); i++)    /* Find mark. */
  947.     ;
  948.     if (i == j) return('Q');        /* If no mark, bad packet. */
  949.     sohp = rcvpkt+i;
  950.  
  951.     rlnpos = ++i;            /* Got it, remember position. */
  952.     if ((j = unchar(rcvpkt[i++])) == 0) { /* Long packet? */
  953.         j = rlnpos + 5;            /* Yes, check header */
  954.         if (j > MAXRP) return('Q');    /* Be defensive. */
  955.         x = rcvpkt[j];            /* Remember header checksum */
  956.         rcvpkt[j] = '\0';
  957.         if (unchar(x) != chk1(rcvpkt+rlnpos))    /* Check header */
  958.         return('Q');
  959.     rcvpkt[j] = (CHAR) x;            /* Restore packet */
  960.     rln = unchar(rcvpkt[j-2]) * 95 + unchar(rcvpkt[j-1]) - bctu;
  961.     j = 3;
  962.     } else {
  963.     rln = j - bctu - 2;        /* Regular packet */
  964.     j = 0;                /* No extended header */
  965.     }
  966.     rsn = unchar(rcvpkt[i++]);        /* Sequence number. */
  967.     type = rcvpkt[i++];            /* Packet type */
  968.     i += j;                /* Skip extended header, if any */
  969.     rdatap = rcvpkt + i;        /* The data itself. */
  970.     j = rln + i;            /* Position of block check. */
  971.     if (j > MAXRP)
  972.     return('Q');            /* Be defensive! */
  973.     for (i = 0; i < bctu; i++)        /* Copy the block check. */
  974.     pbc[i] = rcvpkt[j+i];
  975.     rcvpkt[j] = '\0';
  976.     switch (bctu) {            /* Which block check type? */
  977.     case 1:
  978.         if (unchar(*pbc) != chk1(rcvpkt+rlnpos)) return('Q');
  979.         break;
  980.     case 2:
  981.         x = unchar(*pbc) << 6 | unchar(pbc[1]);
  982.         if (x != chksum(rcvpkt+rlnpos)) return('Q');
  983.         break;
  984.     case 3:
  985.         x = unchar(*pbc) << 12 | unchar(pbc[1]) << 6 | unchar(pbc[2]);
  986.         if (x != chk3(rcvpkt+rlnpos)) return('Q');
  987.         break;
  988.     default:
  989.         error("Impossible block check type.");
  990.     }
  991.     screen(SCR_PT, type, (long) rsn, (char *) sohp);
  992.     return type;            /* Otherwise, return packet type */
  993. }
  994.  
  995. /*
  996.  * CHK3
  997.  * Calculate the 16-bit CRC of a null-terminated string using a
  998.  * byte-oriented tableless algorithm devised by Andy Lowry (Columbia
  999.  * University).  The magic number 010201 is derived from the CRC-CCITT
  1000.  * polynomial x^16+x^12+x^5+1.
  1001.  */
  1002. static unsigned
  1003. chk3(s) CHAR *s; {
  1004.     unsigned c, q;
  1005.     unsigned long crc = 0;
  1006.  
  1007.     while ((c = *s++) != '\0') {
  1008.     if (parity) c &= 0177;
  1009.     q = (crc ^ c) & 017;        /* Low order nybble */
  1010.     crc = (crc >> 4) ^ (q * 010201);
  1011.     q = (crc ^ (c >> 4)) & 017;    /* High order nybble */
  1012.     crc = (crc >> 4) ^ (q * 010201);
  1013.     }
  1014.     return((unsigned) crc);
  1015. }
  1016.  
  1017. /*  G E T P K T -- Fill a packet data field  */
  1018.  
  1019. /*
  1020.  Gets characters from the current source -- file or memory string.
  1021.  Encodes the data into the packet, filling the packet optimally.
  1022.  Set first = 1 when calling for the first time on a given input stream
  1023.  (string or file).
  1024.  
  1025.  Uses global variables:
  1026.  t     -- current character.
  1027.  first -- flag: 1 to start up, 0 for input in progress, -1 for EOF.
  1028.  next  -- next character.
  1029.  data  -- pointer to the packet data buffer.
  1030.  size  -- number of characters in the data buffer.
  1031.  memstr - flag that input is coming from a memory string instead of a file.
  1032.  memptr - pointer to string in memory.
  1033.  (*sx)()  character set translation function
  1034.  
  1035. Returns the size as value of the function, and also sets global "size",
  1036. and fills (and null-terminates) the global data array.  Returns 0 upon eof.
  1037.  
  1038. Rewritten by Paul W. Placeway (PWP) of Ohio State University, March 1989.
  1039. Incorporates old getchx() and encode() inline to eliminate function calls,
  1040. uses buffered input for much-improved efficiency, and clears up some
  1041. confusion with line termination (CRLF vs LF vs CR).
  1042. */
  1043.  
  1044. /*
  1045.  * Below defines for using the C Kermit 5A getpkt() routine in this module.
  1046.  */
  1047. #define NLCHAR '\n'
  1048. #define LF '\n'
  1049. #define SP ' '
  1050. #define DEL 0177
  1051. #define debug(a,b,c,d)
  1052. #define binary (!text)
  1053. #define cxseen cx
  1054. #define fmask 0377
  1055. #define myctlq sctlq
  1056. #define NOCSETS
  1057.  
  1058. static CHAR t, next;
  1059. static int rptn;
  1060.  
  1061. getpkt(bufmax) int bufmax; {        /* Fill one packet buffer */
  1062.     register CHAR rt = t, rnext = next; /* register shadows of the globals */
  1063.     register CHAR *dp, *odp, *p1, *p2;    /* pointers... */
  1064.     register int x;            /* Loop index. */
  1065.     register int a7;            /* Low 7 bits of character */
  1066.     static CHAR leftover[7] = { '\0', '\0', '\0', '\0', '\0', '\0', '\0' };
  1067.  
  1068.     if (first == 1) {        /* If first time thru...  */
  1069.     ffc = 0;
  1070.     first = 0;        /* remember, */
  1071.     *leftover = '\0';       /* discard any interrupted leftovers, */
  1072.     /* get first character of file into t, watching out for null file */
  1073.     if (memstr) {
  1074.         if ((rt = *memptr++) == '\0') { /* end of string ==> EOF */
  1075.         first = -1;
  1076.             size = 0;
  1077.         debug(F100,"getpkt: empty string","",0);
  1078.         return (0);
  1079.         }
  1080.     } else {
  1081.         if ((x = zminchar()) < 0) { /* End of file or input error */
  1082.         first = -1;
  1083.             size = 0;
  1084.         if (x == -2) {        /* Error */
  1085.             debug(F100,"getpkt: input error","",0);
  1086.             cxseen = 1;
  1087.         } else debug(F100,"getpkt: empty file","",0);
  1088.         return(0);
  1089.         }
  1090.         ffc++;            /* Count a file character */
  1091.         rt = x;
  1092.         debug(F101,"getpkt zminchar","",rt);
  1093.     }
  1094.  
  1095. #ifndef NOCSETS
  1096.     debug(F101,"getpkt about to call translate function","",rt);
  1097.     if (!binary && sx) rt = (*sx)(rt); /* Translate */
  1098.     debug(F101," translate function returns","",rt);
  1099. #endif /* NOCSETS */
  1100.  
  1101.     rt &= fmask;            /* bytesize mask */
  1102.  
  1103.     /* PWP: handling of NLCHAR is done later (in the while loop)... */
  1104.  
  1105.     } else if ((first == -1) && (*leftover == '\0')) /* EOF from last time? */
  1106.         return(size = 0);
  1107.  
  1108.     /* Do any leftovers */
  1109.  
  1110.     dp = data;
  1111.     for (p1 = leftover; (*dp = *p1) != '\0'; p1++, dp++) /* copy leftovers */
  1112.         ;
  1113.     *leftover = '\0';
  1114.     if (first == -1)
  1115.       return(size = (dp - data));    /* Handle final leftovers */
  1116.  
  1117.     /* Now fill up the rest of the packet. */
  1118.     rpt = 0;                /* Clear out any old repeat count. */
  1119.     while (first > -1) {        /* Until EOF... */
  1120.     if (memstr) {            /* get next character */
  1121.         if ((rnext = *memptr++) == '\0') { /* end of string ==> EOF */
  1122.         first = -1;        /* Flag eof for next time. */
  1123.         } else {
  1124. #ifndef NOCSETS
  1125.         if (!binary && sx) rnext = (*sx)(rnext); /* Translate */
  1126. #endif /* NOCSETS */
  1127.         ffc++;
  1128.         rnext &= fmask;        /* Bytesize mask. */
  1129.         }
  1130.     } else {
  1131.         if ((x = zminchar()) < 0) { /* End of file or error */
  1132.         first = -1;        /* Flag eof for next time. */
  1133.         if (x == -2) cxseen = 1; /* If error, cancel this file */
  1134.         } else {
  1135. #ifndef NOCSETS
  1136.         if (!binary && sx) x = (*sx)(x); /* Translate */
  1137. #endif /* NOCSETS */
  1138.         rnext = x & fmask;    /* Bytesize mask. */
  1139.         ffc++;            /* Count it */
  1140.         }
  1141.     }
  1142.  
  1143.     /* PWP: handling of NLCHAR is done in a bit...  */
  1144.  
  1145.     odp = dp;            /* Remember current position. */
  1146.  
  1147.     /* PWP: the encode() procedure, in-line (for speed) */
  1148.     if (rptflg) {            /* Repeat processing? */
  1149.         if (
  1150. #ifdef NLCHAR
  1151.         /*
  1152.          * PWP: this is a bit esoteric, so bear with me.
  1153.          * If the next char is really CRLF, then we cannot
  1154.          * be doing a repeat (unless CR,CR,LF which becomes
  1155.          * "~ <n-1> CR CR LF", which is OK but not most efficient).
  1156.          * I just plain don't worry about this case.  The actual
  1157.          * conversion from NL to CRLF is done after the rptflg if...
  1158.          */
  1159.         (binary || (rnext != NLCHAR)) &&
  1160. #endif /* NLCHAR */
  1161.         rt == rnext && (first == 0)) { /* Got a run... */
  1162.         if (++rpt < 94) {    /* Below max, just count */
  1163.             continue;        /* go back and get another */
  1164.         }
  1165.         else if (rpt == 94) {    /* Reached max, must dump */
  1166.             *dp++ = rptq;
  1167.             *dp++ = tochar(rpt);
  1168.             rptn += rpt;
  1169.             rpt = 0;
  1170.         }
  1171.         } else if (rpt == 1) {    /* Run broken, only 2? */
  1172.         /*
  1173.          * PWP: Must encode two characters.  This is handled
  1174.          * later, with a bit of blue smoke and mirrors, after
  1175.          * the first character is encoded.
  1176.          */
  1177.         } else if (rpt > 1) {    /* More than two */
  1178.         *dp++ = rptq;    /* Insert the repeat prefix */
  1179.         *dp++ = tochar(++rpt);    /* and count. */
  1180.         rptn += rpt;
  1181.         rpt = 0;        /* Reset repeat counter. */
  1182.         }
  1183.     }
  1184.  
  1185. #ifdef NLCHAR
  1186.     /*
  1187.      * PWP: even more esoteric NLCHAR handling.  Remember, at
  1188.      * this point t may still be the _system_ NLCHAR.  If so,
  1189.      * we do it here.
  1190.      */
  1191.     if (!binary && (rt == NLCHAR)) {
  1192.         *dp++ = myctlq;    /* just put in the encoding directly */
  1193.         *dp++ = 'M';        /* == ctrl(CR) */
  1194.         if ((dp-data) <= bufmax) odp = dp;    /* check packet bounds */
  1195.         rt = LF;
  1196.     }
  1197. #endif
  1198.  
  1199.     /* meta control stuff fixed by fdc */
  1200.     a7 = rt & 0177;            /* Low 7 bits of character */
  1201.     if (ebqflg && (rt & 0200)) {    /* Do 8th bit prefix if necessary. */
  1202.         *dp++ = ebq;
  1203.         rt = a7;
  1204.     }
  1205.     if ((a7 < SP) || (a7 == DEL)) { /* Do control prefix if necessary */
  1206.         *dp++ = myctlq;
  1207.         rt = ctrl(rt);
  1208.     }
  1209.     if (a7 == myctlq)        /* Prefix the control prefix */
  1210.         *dp++ = myctlq;
  1211.  
  1212.     if ((rptflg) && (a7 == rptq))    /* If it's the repeat prefix, */
  1213.         *dp++ = myctlq;        /* quote it if doing repeat counts. */
  1214.  
  1215.     if ((ebqflg) && (a7 == ebq))    /* Prefix the 8th bit prefix */
  1216.         *dp++ = myctlq;        /* if doing 8th-bit prefixes */
  1217.  
  1218.     *dp++ = rt;            /* Finally, insert the character */
  1219.  
  1220.     if (rpt == 1) {            /* Exactly two copies? */
  1221.         rpt = 0;
  1222.         p2 = dp;            /* save current size temporarily */
  1223.         for (p1 = odp; p1 < p2; p1++) /* copy the old chars over again */
  1224.         *dp++ = *p1;
  1225.         if ((p2-data) <= bufmax) odp = p2; /* check packet bounds */
  1226.     }
  1227.     rt = rnext;            /* Next is now current. */
  1228.     if ((dp-data) >= bufmax) {    /* If too big, save some for next. */
  1229.         size = (dp-data);
  1230.         *dp = '\0';            /* mark (current) the end. */
  1231.         if ((dp-data) > bufmax) {    /* if packet is overfull */
  1232.         for (p1 = leftover, p2=odp; (*p1 = *p2) != '\0'; p1++,p2++)
  1233.             ;
  1234.         debug(F111,"getpkt leftover",leftover,size);
  1235.         debug(F101," osize","",(odp-data));
  1236.         size = (odp-data);    /* Return truncated packet. */
  1237.         *odp = '\0';        /* mark real end */
  1238.         } else {            /* If the packet is exactly full, */
  1239.         debug(F101,"getpkt exact fit","",size);
  1240.         }
  1241.         t = rt; next = rnext;    /* save for next time */
  1242.         return(size);
  1243.     }
  1244.     }                    /* Otherwise, keep filling. */
  1245.     size = (dp-data);
  1246.     *dp = '\0';                /* mark (current) the end. */
  1247.     debug(F111,"getpkt eof/eot",data,size); /* Fell thru before packet full, */
  1248.     return(size);             /* return partially filled last packet. */
  1249. }
  1250.  
  1251. /*
  1252.  * Decodes the data pointed to by the global pointer rdatap.
  1253.  */
  1254. static
  1255. decode() {
  1256.     unsigned a, a7, b8;
  1257.  
  1258.     while ((a = *rdatap++) != '\0') {
  1259.     rpt = 1;            /* Initialize repeat count. */
  1260.     if (rptflg) {            /* Repeat processing? */
  1261.         if (a == rptq) {        /* Yes, have repat prefix? */
  1262.         rpt = unchar(*rdatap++); /* Yes, get count. */
  1263.         a = *rdatap++;        /* and following character. */
  1264.         }
  1265.     }
  1266.     b8 = 0;                /* Assume 8th bit not on. */
  1267.     if (ebqflg) {            /* Doing 8th-bit prefixing? */
  1268.         if (a == ebq) {        /* Yes, have 8th-bit prefix? */
  1269.         b8 = 128;        /* Yes, remember bit 8 on */
  1270.         a = *rdatap++;        /* and get following character. */
  1271.         }
  1272.     }
  1273.     if (a == rctlq) {        /* Is it control prefix? */
  1274.         a = *rdatap++;        /* Yes, get next character */
  1275.         a7 = a & 127;        /* and its low 7 bits. */
  1276.         if (a7 > 62 && a7 < 96)    /* Encoded control character? */
  1277.             a = ctrl(a);        /* Yes, controllify */
  1278.     }
  1279.     a |= b8;            /* OR in the 8th bit. */
  1280.     if (text)
  1281.         if (a == '\r') continue;    /* Discard carriage returns. */
  1282.     for (; rpt > 0; rpt--) {
  1283.         if (osp)
  1284.             *osp++ = a;
  1285.         else if (xflag)        /* If flagged... */
  1286.         tchar(a);        /* ... output to terminal */
  1287.         else {
  1288.             if (zmchout(a) < 0) return -1; /* Output the character. */
  1289.             ffc++;
  1290.         }
  1291.     }
  1292.     }
  1293.     tflush();                /* Flush out message (if xflag) */
  1294.     return(0);
  1295. }
  1296.  
  1297. static
  1298. encstr(s) char *s; {            /* Fill a packet from the string */
  1299.     first = 1;                /* Start lookahead. */
  1300.     memptr = (CHAR *) s;        /* Set input string pointer */
  1301.     memstr = 1;
  1302.     (void) getpkt(spsiz);        /* Fill a packet */
  1303.     memstr = 0;                /* Reset input string pointer */
  1304.     return(size);            /* Return data field length */
  1305. }
  1306.  
  1307. static
  1308. decstr(s) char *s; {            /* Decode packet data into a string */
  1309.     osp = s;                /* Set output string pointer */
  1310.     (void) decode();            /* Decode the string */
  1311.     *osp = '\0';            /* Terminate the string */
  1312.     osp = NULL;                /* Reset output string pointer */
  1313. }
  1314.  
  1315. static
  1316. spar(s) CHAR *s; {            /* Set parameters */
  1317.     int x;
  1318.  
  1319.     s--;                /* Line up with field numbers. */
  1320.  
  1321.     /* Limit on size of outbound packets */
  1322.     x = (rln >= 1) ? unchar(s[1]) : 80;
  1323.     spsiz = (x < 10) ? 80 : x;
  1324.  
  1325.     /* Timeout on inbound packets */
  1326.     x = (rln >= 2) ? unchar(s[2]) : 5;
  1327.     stimo = (x < 0) ? 5 : x;
  1328.  
  1329.  
  1330.     /* Outbound padding */
  1331.     spadn = 0; spadc = '\0';
  1332.     if (rln >= 3) {
  1333.     spadn = unchar(s[3]);
  1334.     if (rln >= 4)
  1335.         spadc = ctrl(s[4]);
  1336.     }
  1337.  
  1338.     /* Outbound packet terminator */
  1339.     seol = (rln >= 5) ? unchar(s[5]) : '\r';
  1340.     if (seol < 2 || seol > 31) seol = '\r';
  1341.  
  1342.     /* Control prefix */
  1343.     x = (rln >= 6) ? s[6] : '#';
  1344.     rctlq = ((x > 32 && x < 63) || (x > 95 && x < 127)) ? x : '#';
  1345.  
  1346.     /* 8th-bit quoting */
  1347.     rq = (rln >= 7) ? s[7] : 0;
  1348.     if (rq == 'Y') rqf = 1;
  1349.     else if ((rq > 32 && rq < 63) || (rq > 95 && rq < 127)) rqf = 2;
  1350.     else rqf = 0;
  1351.  
  1352.     switch (rqf) {
  1353.     case 0: ebqflg = 0; break;
  1354.     case 1: if (parity) { ebqflg = 1; ebq = '&'; } break;
  1355.     case 2: if (ebqflg = (ebq == sq || sq == 'Y')) ebq = rq;
  1356.     }
  1357.  
  1358.     /* Block check */
  1359.     x = 1;
  1360.     if (rln >= 8) {
  1361.     x = s[8] - '0';
  1362.     if (x < 1 || x > 3) x = 1;
  1363.     }
  1364.     bctr = x;
  1365.  
  1366.     /* Repeat prefix */
  1367.     if (rln >= 9) {
  1368.     rptq = s[9];
  1369.     rptflg = ((rptq > 32 && rptq < 63) || (rptq > 95 && rptq < 127));
  1370.     } else rptflg = 0;
  1371.  
  1372.     /* Capabilities */
  1373.     atcapu = lpcapu = swcapu = 0;    /* No capabilities by default    */
  1374.     if (rln >= 10) {
  1375.     x = unchar(s[10]);
  1376.     atcapu = (x & atcapb) && atcapr;    /* Attribute packets */
  1377.     lpcapu = (x & lpcapb) && lpcapr;    /* Long packets */
  1378.     swcapu = (x & swcapb) && swcapr;    /* Sliding windows */
  1379.     for (capas = 10; (unchar(s[capas]) & 1) && (rln >= capas); capas++)
  1380.         ;                    /* Skip to capas + 1 */
  1381.     }
  1382.  
  1383.     /* Long packets */
  1384.     if (lpcapu) {            /* Flag set above */
  1385.     if (rln > capas+2) {
  1386.         x = unchar(s[capas+2]) * 95 + unchar(s[capas+3]);
  1387.         spsiz = x > MAXSP ? MAXSP : x;
  1388.     }
  1389.     if (spsiz < 10) spsiz = 80;    /* Be defensive... */
  1390.     }
  1391.  
  1392.     /* Sliding windows */
  1393.     if (swcapu) {
  1394.     if (rln > capas+1) {
  1395.         x = unchar(s[capas+1]);
  1396.         wsize = x > MAXWS ? MAXWS : x;
  1397.     } else
  1398.         wsize = 1;
  1399.     }
  1400. }
  1401.  
  1402. /* Fill the array with my send-init parameters */
  1403.  
  1404. static char *
  1405. rpar() {
  1406.     data[1] = tochar(DRPSIZ);        /* Biggest packet I can receive */
  1407.     data[2] = tochar(rtimo);        /* When I want to be timed out */
  1408.     data[3] = tochar(rpadn);        /* How much padding I need */
  1409.     data[4] = ctrl(rpadc);        /* Padding character I want */
  1410.     data[5] = tochar(reol);        /* End-of-Line character I want */
  1411.     data[6] = sctlq;            /* Control-Quote character I send */
  1412.     switch(rqf) {            /* 8th-bit prefix */
  1413.     case -1:
  1414.     case  1: if (parity) ebq = sq = '&'; break;
  1415.     case  0:
  1416.     case  2: break;
  1417.     }
  1418.     data[7] = sq;
  1419.     data[8] = bctr + '0';        /* Block Check Type */
  1420.     if (rptflg) data[9] = rptq; else data[9] = '~';
  1421.     data[10] = tochar(atcapr?atcapb:0 | lpcapr?lpcapb:0 | swcapr?swcapb:0);
  1422.     capas = 10;
  1423.     data[capas+1] = tochar(swcapr ? wsize : 0);    /* Window size */
  1424.     data[capas+2] = tochar(rpsiz / 95);    /* Long packet size */
  1425.     data[capas+3] = tochar(rpsiz % 95);    /* ... */
  1426.     data[capas+4] = '\0';
  1427.     return((char *) (data+1));        /* Return a pointer to the string */
  1428. }
  1429.  
  1430. /*
  1431.  * proto()--Kermit protocol entry point.  Set your start state and call
  1432.  * this, NOT wart().  Modified to set long packets capability on the
  1433.  * basis of the packet size set in the external user interface.
  1434.  */
  1435. void
  1436. proto()
  1437. {
  1438. #ifdef XPRKERMIT
  1439.     struct XPR_UPDATE xpru;
  1440.  
  1441.     xpru.xpru_protocol = "XPR-Kermit";
  1442.     xpru.xpru_updatemask = XPRU_PROTOCOL;
  1443.     calla(xupdate, &xpru);
  1444.     zclear();
  1445. #endif
  1446.     sndpkt = malloc(MAXSP+100);
  1447.     rcvpkt = malloc(MAXRP+200);
  1448.     data = malloc(MAXSP+50);
  1449.     zinbuffer = malloc(INBUFSIZE);
  1450.     zoutbuffer = malloc(OBUFSIZE);
  1451.     if (urpsiz > 94) {                /* Long packets? */
  1452.     rpsiz = (urpsiz > MAXRP - 20 ? MAXRP - 20 : urpsiz);
  1453.     lpcapr = 1;                /* Request long packets */
  1454.     } else {                    /* No long packets */
  1455.     lpcapr = 0;
  1456.     if (urpsiz < 10)            /* Too small?    */
  1457.         rpsiz = 80;
  1458.     else
  1459.         rpsiz = DRPSIZ;
  1460.     }
  1461.     urpsiz = rpsiz;
  1462.     cx = cz = 0;                /* Haven't aborted yet */
  1463.     if (bctr < 1)
  1464.     bctr = 1;            /* Legal block check? */
  1465.     if (bctr > 3)
  1466.     bctr = 3;
  1467.     if (sndpkt == NULL || rcvpkt == NULL || data == NULL || zinbuffer == NULL ||
  1468.         zoutbuffer == NULL)
  1469. #ifdef XPRKERMIT
  1470.     ST_Display_String(STMsg,"Can't allocate memory");
  1471. #else
  1472.     tmsgl("Can't allocate memory for Kermit!!");
  1473. #endif
  1474.     else
  1475.     wart();
  1476.     if (sndpkt) { free(sndpkt); sndpkt = NULL; }
  1477.     if (rcvpkt) { free(rcvpkt); rcvpkt = NULL; }
  1478.     if (data) { free(data); data = NULL; }
  1479.     if (zinbuffer) { free(zinbuffer); zinbuffer = NULL; }
  1480.     if (zoutbuffer) { free(zoutbuffer); zoutbuffer = NULL; }
  1481. }
  1482.  
  1483. /*
  1484.  * That ends the system-independent Kermit modules.  What follows
  1485.  * are the system-dependent ones.
  1486.  */
  1487.  
  1488. /*
  1489.  * File I/O modules for XPR Kermit.
  1490.  */
  1491. #define EOF -1
  1492. typedef struct FILE FILE;
  1493.  
  1494. static FILE *ifp = NULL, *ofp = NULL;
  1495.  
  1496. static
  1497. zclear()
  1498. {
  1499.     ifp = NULL; ofp = NULL;
  1500. }
  1501.  
  1502. static
  1503. zopeni(name) char *name; {
  1504.  
  1505.     zincnt = 0;
  1506.     ifp = (FILE *) callaa(xfopen, name, "r");
  1507.     if (ifp == NULL)
  1508.     return -1;
  1509.     else
  1510.     return 0;
  1511. }
  1512.  
  1513. #include <dos/dos.h>
  1514. #include <clib/dos_protos.h>
  1515. #include <pragmas/dos_pragmas.h>
  1516.  
  1517. static
  1518. zopeno(name) char *name; {
  1519.  
  1520.     zoutcnt = 0;
  1521.     zoutptr = zoutbuffer;
  1522.  
  1523.     ofp = (FILE *) callaa(xfopen, name, "w");
  1524.     if (ofp == NULL)
  1525.     return -1;
  1526.     else
  1527.     return 0;
  1528. }
  1529.  
  1530. static
  1531. zclosi() {
  1532.     int x;
  1533.  
  1534.     if (ifp == NULL)
  1535.     return 0;
  1536.     x = calla(xfclose, ifp);
  1537.     ifp = NULL;
  1538.     if (x < 0)
  1539.     return -1;
  1540.     else
  1541.     return 0;
  1542. }
  1543.  
  1544. static
  1545. zcloso(discard) int discard; {
  1546.     int x;
  1547.  
  1548.     if (ofp == NULL)
  1549.     return 0;
  1550.     if (zoutcnt > 0)
  1551.         if (zoutdump() != 0)
  1552.             return -1;
  1553.     x = calla(xfclose, ofp);
  1554.     ofp = NULL;
  1555.     if (x < 0)
  1556.     return -1;
  1557.     else if (discard) {
  1558.     if (xunlink != NULL) {
  1559.         if (calla(xunlink, myname) < 0) {
  1560.         return -1;
  1561.         }
  1562.     }
  1563.     return 0;
  1564.     }
  1565.     return 0;
  1566. }
  1567.  
  1568. #include <ctype.h>
  1569.  
  1570. extern int convert;        /* 0 for literal files, 1 for translate */
  1571.  
  1572. /*  Z R T O L  --  Convert remote filename into local form  */
  1573.  
  1574. /*  For AMIGA, this means changing uppercase letters to lowercase.  */
  1575.  
  1576. zrtol(name,name2,mywarn) char *name, *name2; int mywarn; {
  1577.     if (convert) {
  1578.         for ( ; *name != '\0'; name++) {
  1579.             *name2++ = isupper(*name) ? tolower(*name) : *name;
  1580.         }
  1581.         *name2 = '\0';
  1582.     } else
  1583.         strcpy(name2,name);
  1584. }
  1585.  
  1586. /* name from local to remote format */
  1587.  
  1588. static
  1589. zltor(s1,s2) char *s1, *s2; {
  1590.     char *EndPath();
  1591.     char dotseen = 0;
  1592.  
  1593.     if (!convert)
  1594.     strcpy(s2, s1);
  1595.     else {
  1596.     s1 = EndPath(s1);    /* strip dir/disk */
  1597.     while (*s1 != '\0') {
  1598.         if (islower(*s1))
  1599.         *s2 = toupper(*s1);
  1600.         else if (isalnum(*s1))
  1601.         *s2 = *s1;
  1602.         else if (*s1 == '.')
  1603.         if (!dotseen) {
  1604.             dotseen = 1;
  1605.             *s2 = *s1;
  1606.         } else
  1607.             *s2 = 'X';
  1608.         /* else a character we're not prepared to handle. */
  1609.         s1++; s2++;
  1610.         }
  1611.     *s2 = '\0';
  1612.     }
  1613. }
  1614.  
  1615. /*
  1616.  * System-dependent function to do buffered input and output.
  1617.  * Text conversion now done in the packet routines.
  1618.  */
  1619. static
  1620. zinfill(void) {
  1621.     zincnt = calladda(xfread, zinbuffer, sizeof (char), INBUFSIZE, ifp);
  1622.     if (zincnt == 0) return (-1); /* end of file */
  1623.     zinptr = zinbuffer;       /* set pointer to beginning, (== &zinbuffer[0]) */
  1624.     zincnt--;            /* one less char in buffer */
  1625.     return((int)(*zinptr++) & 0377); /* because we return the first */
  1626. }
  1627.  
  1628. static
  1629. zoutdump(void) {
  1630.     zoutptr = zoutbuffer;        /* reset buffer pointer in all cases */
  1631.     if (zoutcnt == 0) {            /* nothing to output */
  1632.     return(0);
  1633.     } else if (zoutcnt < 0) {        /* unexpected negative value */
  1634.     zoutcnt = 0;            /* reset output buffer count */
  1635.     return(-1);            /* and fail. */
  1636.     }
  1637.     if (calladda(xfwrite, zoutbuffer, sizeof (char), zoutcnt, ofp)) {
  1638.     zoutcnt = 0;            /* reset output buffer count */
  1639.     return(0);            /* things worked OK */
  1640.     } else {
  1641.     zoutcnt = 0;            /* reset output buffer count */
  1642.     return(-1);            /* error return */
  1643.     }
  1644. }
  1645.  
  1646. int ttol(s, n)
  1647. char *s;
  1648. int n;
  1649. {
  1650.     long status;
  1651.  
  1652.     status = callad(xswrite, s, (long) n);
  1653.     if (status == 0) return(n);
  1654.     else return(-1);
  1655. }
  1656.  
  1657. #include "timer.h"
  1658. #include <clib/exec_protos.h>
  1659. #include <pragmas/exec_pragmas.h>
  1660.  
  1661. #ifdef MYREAD
  1662. /* Private buffer for myread() and its companions.  Not for use by anything
  1663.  * else.  ttflui() is allowed to reset them to initial values.  ttchk() is
  1664.  * allowed to read my_count.
  1665.  *
  1666.  * my_item is an index into mybuf[].  Increment it *before* reading mybuf[].
  1667.  *
  1668.  * A global parity mask variable could be useful too.  We could use it to
  1669.  * let myread() strip the parity on its own, instead of stripping sign
  1670.  * bits as it does now.
  1671.  */
  1672.  
  1673. #define MYBUFLEN 256
  1674. static CHAR mybuf[MYBUFLEN];        /* Buffer, including push back */
  1675. static int my_count = 0;        /* Number of chars still in mybuf */
  1676. static int my_item = -1;        /* Last index read from mybuf[] */
  1677.  
  1678. /* myread() -- Efficient read of one character from communications line.
  1679.  *
  1680.  * Uses a private buffer to minimize the number of expensive read() system
  1681.  * calls.  Essentially performs the equivalent of read() of 1 character, which
  1682.  * is then returned.  By reading all available input from the system buffers
  1683.  * to the private buffer in one chunk, and then working from this buffer, the
  1684.  * number of system calls is reduced in any case where more than one character
  1685.  * arrives during the processing of the previous chunk, for instance high
  1686.  * baud rates or network type connections where input arrives in packets.
  1687.  * If the time needed for a read() system call approaches the time for more
  1688.  * than one character to arrive, then this mechanism automatically compensates
  1689.  * for that by performing bigger read()s less frequently.  If the system load
  1690.  * is high, the same mechanism compensates for that too.
  1691.  *
  1692.  * myread() is a macro that returns the next character from the buffer.  If the
  1693.  * buffer is empty, mygetbuf() is called.  See mygetbuf() for possible error
  1694.  * returns.
  1695.  *
  1696.  * This should be efficient enough for any one-character-at-a-time loops.
  1697.  * For even better efficiency you might use memcpy()/bcopy() or such between
  1698.  * buffers (since they are often better optimized for copying), but it may not
  1699.  * be worth it if you have to take an extra pass over the buffer to strip
  1700.  * parity and check for CTRL-C anyway.
  1701.  *
  1702.  * Note that if you have been using myread() from another program module, you
  1703.  * may have some trouble accessing this macro version and the private variables
  1704.  * it uses.  In that case, just add a function in this module, that invokes the
  1705.  * macro.
  1706.  */
  1707. #define myread(timo)  (--my_count < 0 ? mygetbuf(timo) : 255 & (int)mybuf[++my_item])
  1708.  
  1709. /*
  1710.  * System-dependent mygetbuf() routine.  Fills buffer with as many characters
  1711.  * as it can get, provided it can get the next one within timo seconds.
  1712.  * Returns the number of characters read, or 0 if none were read within
  1713.  * timo seconds, or a negative value if some other error occured.
  1714.  */
  1715. static int
  1716. myfillbuf(int timo) {
  1717.     long n;
  1718.  
  1719.     /*
  1720.      * Find out how many characters are available, if any.
  1721.      * We can only do this if xsquery is non-NULL.
  1722.      */
  1723.     if (xsquery != NULL && (n = (*xsquery)()) > 0) {
  1724.         calladd(xsread, mybuf, n, 0L);
  1725.         return n;
  1726.     } else
  1727.         /*
  1728.          * xsread() returns exactly what we want: zero if no
  1729.          * character is received within timo seconds, and -1
  1730.          * on error.  Might as well ask for a bufferful,
  1731.          * provided first one arrives soon enough.
  1732.          */
  1733.         return(calladd(xsread, &mybuf[0], (long) MYBUFLEN ,
  1734.                                timo*1000000L));
  1735. }
  1736.  
  1737. /* mygetbuf(timo) -- Fill buffer for myread() and return first character,
  1738.  * within timo seconds.
  1739.  *
  1740.  * This function is what myread() uses when it can't get the next character
  1741.  * directly from its buffer.  First, it calls a system dependent myfillbuf()
  1742.  * to read at least one new character into the buffer, and then it returns
  1743.  * the first character just as myread() would have done.  This function also
  1744.  * is responsible for all error conditions that myread() can indicate.
  1745.  *
  1746.  * Returns: When OK    => a positive character, 0 or greater.
  1747.  *          When TIMEOUT=> -1
  1748.  *        When error    => -2.
  1749.  *
  1750.  */
  1751. static int
  1752. mygetbuf(int timo) {
  1753.     my_count = myfillbuf(timo);
  1754.     if (my_count <= 0)
  1755.       return(my_count - 1);
  1756.     --my_count;
  1757.     return(255 & (int)mybuf[my_item = 0]);
  1758. }
  1759. #endif /*MYREAD*/
  1760.  
  1761. /*
  1762.  * T T I N L
  1763.  *
  1764.  * Return a line in the buffer pointed to by s from the serial line.
  1765.  * The line must end with eol and be no longer than max characters.
  1766.  * timeout is a timeout interval in seconds.
  1767.  *
  1768.  * Returns
  1769.  *    > 0    Success--number of characters read
  1770.  *    = 0    Shouldn't happen!
  1771.  *     -1    Timeout
  1772.  *    -2    Error of some other kind
  1773.  *
  1774.  * This version for XPR Kermit.  We ignore negative returns from
  1775.  * the xpr_sread() function, preferring to take care of these
  1776.  * via the timeout mechanism.
  1777.  */
  1778. int ttinl(s, max, eol, timeout)
  1779. char *s;
  1780. int max, timeout, eol;
  1781. {
  1782.     int x = 0;
  1783.     long i;
  1784.     struct timerequest *Timereq;
  1785.     unsigned mask;
  1786.  
  1787.     *s = '\0';
  1788.     mask = (parity ? 0177 : 0377);
  1789.     /*
  1790.      * Set up and post timer request for overall timeout.
  1791.      * As a compromise between correct and efficient, I only check
  1792.      * the overall timeout if a one-character read with a one second
  1793.      * timeout fails first.
  1794.      */
  1795.     if (!(Timereq = CreateTimer(UNIT_VBLANK)))
  1796.         return -1;
  1797.     Timereq->tr_time.tv_secs = timeout;
  1798.     Timereq->tr_time.tv_micro = 0;
  1799.     Timereq->tr_node.io_Command = TR_ADDREQUEST;
  1800.     SendIO((struct IORequest *) Timereq);
  1801. #ifndef MYREAD
  1802.     /*
  1803.      * Willy Langeveld assures me that, since serial.device does its
  1804.      * own buffering, calling xsread once for each character isn't
  1805.      * going to take too long.
  1806.      *
  1807.      */
  1808.     for (x = 0; x < max; ) {
  1809.         if ((i = calladd(xsread, s, 1L, 1000000L)) < 0) {
  1810.             if (chkint() < 0) {
  1811.                 x =  -2;
  1812.                 goto leave;
  1813.             }
  1814.         } else if (i == 1) {
  1815.             x++;
  1816.             if ((*s++ &= mask) == eol)
  1817.                 break;
  1818.         } else if (CheckIO((struct IORequest *) Timereq)) { /* timeout */
  1819.             x = -1;            /* Flag timeout abort */
  1820.             goto leave;
  1821.         }
  1822.     }
  1823.     *s = '\0';                /* Normal termination */
  1824.     leave:                    /* Common cleanup code */
  1825.     AbortIO((struct IORequest *) Timereq);
  1826.     WaitIO((struct IORequest *) Timereq);
  1827.     DeleteTimer(Timereq);
  1828.     return(x);
  1829. #else
  1830.     /*
  1831.      * The following call to myread sets up a 1 second per-character
  1832.      * timeout.  We have to be careful not to return from ttinl until
  1833.      * the entire timeout interval has passed, however.
  1834.      */
  1835.  
  1836.     for (x = 0; x < max; ) {
  1837.         if ((*s = myread(1)) < -1) {
  1838.             /*
  1839.              * The following code deals with the case that
  1840.              * xsread() returns a negative value if the
  1841.              * user has clicked on the "Cancel File" or
  1842.              * "Cancel Batch" gadgets.  However, we don't
  1843.              * want to abort receiving the current packet
  1844.              * in this case;  calling chkint() now sets
  1845.              * the global cx and/or cz flags, but in the
  1846.              * case of a complete abort, chkint() returns
  1847.              * a negative value.
  1848.              */
  1849.             if (chkint() < 0) {
  1850.                 x = -2;        /* Error */
  1851.                 goto leave;
  1852.             }
  1853.         } else if (CheckIO((struct IORequest *) Timereq)) { /* timeout */
  1854.             x = -1;            /* Flag timeout abort */
  1855.             goto leave;
  1856.         } else if (*s >= 0) {        /* Successful get of character */
  1857.             x++;
  1858.             if ((*s++ &= mask) == eol)
  1859.                 break;
  1860.         }
  1861.         
  1862.     }
  1863.     *s = '\0';                /* Normal termination */
  1864.     leave:                    /* Common cleanup code */
  1865.     AbortIO((struct IORequest *) Timereq);
  1866.     WaitIO((struct IORequest *) Timereq);
  1867.     DeleteTimer(Timereq);
  1868.     return(x);
  1869. #endif /*MYREAD*/
  1870. }
  1871.  
  1872. /*
  1873.  * This is the XPR Kermit version of chkint.  We allow multiple levels
  1874.  * of interrupt, if available.
  1875.  */
  1876. int chkint(void)            /* Check for console interrupts. */
  1877. {
  1878.     int x;
  1879.  
  1880.     x = (*xchkabort)();
  1881.     switch (x) {
  1882.         case 0:            /* No abort pending */
  1883.             return 0;
  1884.         case 1:            /* Abort file only. */
  1885.             cx = 1;
  1886.             break;
  1887.         case 2:            /* Abort file and batch. */
  1888.             cx = cz = 1;
  1889.             break;
  1890.         case -1:        /* Emergency escape -- kill all */
  1891.             cx = cz = 1;
  1892.             return -1;
  1893.         default:
  1894.             ;
  1895.     }
  1896.     return 1;
  1897. }
  1898.  
  1899. void ttflui()
  1900. {
  1901.     (void) (*xsflush)();
  1902. #ifdef MYREAD
  1903.     my_count = 0;
  1904.     my_item = -1;
  1905. #endif
  1906. }
  1907.  
  1908. void sleep(sec)
  1909. int sec;
  1910. {
  1911.     struct timeval tv;
  1912.  
  1913.     if (sec) {
  1914.         tv.tv_secs = sec;
  1915.         tv.tv_micro = 0;
  1916.         MyDelay(&tv, UNIT_VBLANK);
  1917.     }
  1918. }
  1919.  
  1920. #define MAXMESSAGE 50
  1921. static char message[MAXMESSAGE+1];
  1922. static int nmess = 0;
  1923. static long errors = 0, blocks = 0;
  1924.  
  1925. /*  screen(f,c,n,s)
  1926.       f - argument descriptor
  1927.       c - a character or small integer
  1928.       n - a long integer
  1929.       s - a string.
  1930.  Fill in this routine with the appropriate display update for the system.
  1931.  This version for XPR Kermit.
  1932. */
  1933.  
  1934. screen(f,c,n,s) int f; long n; char c; char *s; {
  1935.     struct XPR_UPDATE xpru;
  1936.  
  1937.     if (!local || xflag) return;
  1938.     switch (f) {
  1939.     case SCR_PT:            /* Packet Transferred. */
  1940.     if (c == 'Y') return;        /* Don't bother with ACK's. */
  1941.     xpru.xpru_packettype = c;
  1942.     xpru.xpru_blocksize = strlen(s);
  1943.     xpru.xpru_blocks = ++blocks;
  1944.     if (c == 'D' || c == 'Z') {    /* If data or EOF packet ... */
  1945.         xpru.xpru_bytes = ffc;    /* ... update transfer count */
  1946.         xpru.xpru_updatemask = XPRU_BYTES;
  1947.     } else if (c == 'T') {        /* Timeout */
  1948.         xpru.xpru_timeouts = timeouts++;
  1949.         xpru.xpru_updatemask = XPRU_TIMEOUTS;
  1950.         } else
  1951.         xpru.xpru_updatemask = 0;
  1952.     xpru.xpru_updatemask |= XPRU_PACKETTYPE | XPRU_BLOCKSIZE |
  1953.         XPRU_BLOCKS;
  1954.     break;
  1955.     case SCR_EM:            /* Error message. */
  1956.     xpru.xpru_errormsg = s;
  1957.     xpru.xpru_updatemask = XPRU_ERRORMSG;
  1958.     break;
  1959.     default:
  1960.     return;
  1961.     }
  1962.     calla(xupdate, &xpru);
  1963. }
  1964.  
  1965. void tchar(c)
  1966. char c;
  1967. {
  1968.     struct XPR_UPDATE xpru;
  1969.  
  1970.     if (c == '%') {        /* retry */
  1971.         xpru.xpru_errors = ++errors;
  1972.         xpru.xpru_updatemask = XPRU_ERRORS;
  1973.     } else if (c == '#') { /* fake it */
  1974.         xpru.xpru_errors = errors = 0;
  1975.         xpru.xpru_blocks = blocks = 0;
  1976.         nmess = 0;            /* Make sure message empty. */
  1977.         xpru.xpru_updatemask = XPRU_BLOCKS | XPRU_ERRORS;
  1978.     } else {
  1979.         message[nmess++] = c;
  1980.         if (nmess >= MAXMESSAGE)
  1981.             tflush();
  1982.         return;
  1983.     }
  1984.     calla(xupdate, &xpru);
  1985. }
  1986.  
  1987. static
  1988. tflush()
  1989. {
  1990.     struct XPR_UPDATE xpru;
  1991.  
  1992.     if (nmess <= 0)
  1993.         return;
  1994.     message[nmess] = '\0';
  1995.     xpru.xpru_errormsg = message;
  1996.     xpru.xpru_updatemask = XPRU_ERRORMSG;
  1997.     calla(xupdate, &xpru);
  1998.     nmess = 0;
  1999. }
  2000.  
  2001. ST_Display_String(Item, S)
  2002. int Item;
  2003. char *S;
  2004. {
  2005.   struct XPR_UPDATE xpru;
  2006.  
  2007.   switch (Item) {
  2008.   case STMsg:
  2009.       xpru.xpru_msg = S;
  2010.     xpru.xpru_updatemask = XPRU_MSG; break;
  2011.   case STFile:
  2012.       xpru.xpru_filename = S;
  2013.     xpru.xpru_updatemask = XPRU_FILENAME; break;
  2014.   case STUplSize:
  2015.       xpru.xpru_filesize = callad(xfinfo, S, 1L);
  2016.     xpru.xpru_updatemask = XPRU_FILESIZE; break;
  2017.   default:
  2018.     return;
  2019.   }
  2020.   calla(xupdate, &xpru);
  2021. }
  2022.  
  2023. ST_Display_CRC(Item)
  2024. int Item;
  2025. {
  2026.   struct XPR_UPDATE xpru;
  2027.  
  2028.   switch (Item) {
  2029.   case 1:
  2030.       xpru.xpru_blockcheck = "Check-6"; break;
  2031.   case 2:
  2032.       xpru.xpru_blockcheck = "Check-12"; break;
  2033.   case 3:
  2034.       xpru.xpru_blockcheck = "CRC-16"; break;
  2035.   default:
  2036.     return;
  2037.   }
  2038.   xpru.xpru_updatemask = XPRU_BLOCKCHECK;
  2039.  
  2040.   calla(xupdate, &xpru);
  2041. }
  2042.  
  2043. extern char *p_pattern;
  2044.  
  2045. #ifndef TRUE
  2046. #define TRUE    1
  2047. #define FALSE    0
  2048. #endif
  2049.  
  2050. static int firsttime = TRUE;
  2051.  
  2052. int gnfile(fname, len)
  2053. char *fname;
  2054. int len;    /* it is 50 */
  2055. {
  2056.     char buffer[256];
  2057.     static long gnstate;
  2058.  
  2059.     if (firsttime) {
  2060.         gnstate = callaa(xffirst, buffer, p_pattern);
  2061.         if (gnstate) firsttime = FALSE;
  2062.     } else {
  2063.         gnstate = calldaa(xfnext, gnstate, buffer, p_pattern);
  2064.         if (gnstate == 0L) firsttime = TRUE;
  2065.     }
  2066.     if (gnstate && (int)strlen(buffer) < len) {
  2067.         strcpy(fname, buffer);
  2068.         return((int)gnstate);
  2069.     } else    return(0);
  2070. }
  2071.  
  2072. void gninit(void) {
  2073.     firsttime = TRUE;
  2074. }
  2075.  
  2076. char *EndPath(p)
  2077. char *p;
  2078. {
  2079.     char *q;
  2080.  
  2081.     q = p;
  2082.     while (*p != '\0') {
  2083.         if ((*p == '/') || (*p == ':'))
  2084.             q = p + 1;
  2085.         p++;
  2086.     }
  2087.     return(q);
  2088. }
  2089.